﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Security.Cryptography;

/// 
/// Contains an extended implementation of the BitArray class,
/// essentially for IP mask operations
/// 

namespace InterPC.SPF {

    /// <summary>
    /// Extend the BitArray Class by adding mask opérations and equality comparaisons capabilities
    /// </summary>
    internal class BitArrayEx {

        /// <summary>
        /// The main BitArray object
        /// </summary>
        private BitArray _Array;

        #region BitArray native functions

        // Because BitArray class cannot be inherited
        // All base functionnalities are wrapped here

        public bool this[int index] {
            get { return _Array[index]; }
            set { _Array[index] = value; }
        }

        public int Count { get { return _Array.Count; } }
        public int Length {
            get { return _Array.Length; }
            set { _Array.Length = value; }
        }

        public BitArrayEx(BitArray bits) { _Array = new BitArray(bits); }
        public BitArrayEx(bool[] values) { _Array = new BitArray(values); }
        public BitArrayEx(byte[] bytes) { _Array = new BitArray(bytes); }
        public BitArrayEx(int length) { _Array = new BitArray(length); }
        public BitArrayEx(int[] values) { _Array = new BitArray(values); }
        public BitArrayEx(int length, bool defaultValue) { _Array = new BitArray(length, defaultValue); }

        public bool Get(int index) { return _Array.Get(index); }
        public void Set(int index, bool value) { _Array.Set(index, value); }
        public void SetAll(bool value) { _Array.SetAll(value); }

        public BitArray And(BitArray value) { return _Array.And(value); }
        public BitArray Or(BitArray value) { return _Array.Or(value); }
        public BitArray XOr(BitArray value) { return _Array.Xor(value); }
        public BitArray Not(BitArray value) { return _Array.Not(); }

        public void CopyTo(Array array, int index) { _Array.CopyTo(array, index); }

        #endregion
        
        /// <summary>
        /// Are equals if all bit are equals one to one
        /// </summary>
        public override bool Equals(object o) {
            BitArrayEx arrayToCompare = o as BitArrayEx;
            if (arrayToCompare == null)
                return false;

            if (this.Length != arrayToCompare.Length)
                return false;

            for (int i = 0; i < this.Length; i++)
                if (this[i] != arrayToCompare[i])
                    return false;

            return true;
        }

        /// <summary>
        /// Générate a representative hash code faor the current
        /// content representation of the array
        /// </summary>
        public override int GetHashCode() {
            MD5 md5 = MD5.Create();
            byte[] HashCode = md5.ComputeHash(MD5.Create(this.ToString()).Hash, 0, 4);
            return BitConverter.ToInt32(HashCode, 0);
        }

        /// <summary>
        /// Apply an ip mask to the array (all the mask surface is set to false)
        /// </summary>
        public void ApplyMask(int Mask) {

            int nbBytes = this.Length / 8;
            int reste = this.Length % 8;
            if (reste > 0)
                nbBytes++;

            int currByte = 0;
            int currBitInByte = 7;

            int posInMask = 0;

            while (currByte < nbBytes) {

                this[(currByte * 8) + currBitInByte] = posInMask < Mask ? this[(currByte * 8) + currBitInByte] : false;
                
                posInMask++;

                if (currBitInByte == 0) {
                    currBitInByte = (reste > 0 && currByte == (nbBytes - 1)) ? reste - 1 : 7;
                    currByte++;
                }
                else
                    currBitInByte--;

            }

            
        }

        /// <summary>
        /// Returns a "1" &amp; "0" string representation of the array
        /// </summary>
        public override string ToString() {

            StringBuilder BitsRepresentation = new StringBuilder();
            for (int i = 0; i < this.Length; i++)
                BitsRepresentation.Append(this[i] ? "1" : "0");

            return string.Format("BitArrayEx {{{0}}}", BitsRepresentation);

        }

        /// <summary>
        /// Overwrite the == operator for quick comparisons
        /// </summary>
        public static bool operator ==(BitArrayEx a, BitArrayEx b) {
            // If both are null, or both are same instance, return true.
            if (System.Object.ReferenceEquals(a, b)) {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object)a == null) || ((object)b == null)) {
                return false;
            }

            return a.Equals(b);
        }

        /// <summary>
        /// Overwrite the == operator for quick comparisons
        /// </summary>
        public static bool operator !=(BitArrayEx a, BitArrayEx b) {
            return !(a == b);
        }
    }

}
